﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

#nullable disable
namespace BeetleX.XRPC.Clients
{
  public class ControllerCenter
  {
    private ConcurrentDictionary<string, ControllerCenter.HandlerItem> mHandlers = new ConcurrentDictionary<string, ControllerCenter.HandlerItem>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);

    public void Register<Service>(Service serviceImpl)
    {
      Type type = typeof (Service);
      if (!type.IsInterface)
        throw new XRPCException(string.Format("{0} not interface!", (object) type));
      if (!serviceImpl.GetType().IsClass)
        throw new XRPCException(string.Format("{0} not the implementer!", (object) serviceImpl));
      foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public))
      {
        string key = "/" + type.Name + "/" + method.Name;
        ControllerCenter.HandlerItem handlerItem = new ControllerCenter.HandlerItem()
        {
          Controller = (object) serviceImpl,
          Url = key,
          Handler = new ClientActionHandler(method)
        };
        handlerItem.Parameters = ((IEnumerable<ParameterInfo>) method.GetParameters()).Select<ParameterInfo, Type>((Func<ParameterInfo, Type>) (a => a.ParameterType)).ToArray<Type>();
        this.mHandlers[key] = handlerItem;
      }
    }

    public ControllerCenter.HandlerItem GetHandler(string url)
    {
      ControllerCenter.HandlerItem handler;
      this.mHandlers.TryGetValue(url, out handler);
      return handler;
    }

    public class HandlerItem
    {
      public string Url { get; internal set; }

      public object Controller { get; internal set; }

      public ClientActionHandler Handler { get; internal set; }

      public Type[] Parameters { get; internal set; }

      public object GetValue(object result)
      {
        if (this.Handler.IsVoid)
          return (object) null;
        if (!this.Handler.IsTaskResult)
          return (object) null;
        return this.Handler.ResultProperty != null ? this.Handler.ResultPropertyInfo.GetValue(result) : (object) null;
      }
    }
  }
}
